Skip to content

Add structural reranking to code search - #12

Merged
tae2089 merged 1 commit into
mainfrom
worktree-search-rerank-tier0
Jul 11, 2026
Merged

Add structural reranking to code search#12
tae2089 merged 1 commit into
mainfrom
worktree-search-rerank-tier0

Conversation

@tae2089

@tae2089 tae2089 commented Jul 11, 2026

Copy link
Copy Markdown
Owner

배경

ccg search(CLI)와 MCP search 도구가 FTS 후보를 raw BM25 순서 그대로 반환했다.
동의어·오타·내부 단어 쿼리에서 관련도 높은 심볼이 상위로 오지 못했다.

DeusData/codebase-memory-mcp의 "combined scoring" 아이디어를 임베딩/외부 서비스
없이 차용한 Tier-0 개선이다.

변경

  • 신규 internal/searchrank — 의존성 없는 리랭커. FTS rank와 두 구조 신호를
    Reciprocal Rank Fusion으로 융합:
    • 이름 fuzzy 유사도: rune Levenshtein (전체 이름 + camelCase 서브토큰 + 오타용
      join된 쿼리).
    • 경로 근접: 쿼리 토큰이 파일 경로 세그먼트와 겹치는 비율.
  • 이름 신호를 경로보다 높게 가중 → 정확한 이름 일치가 단순 같은-파일 히트보다 우선.
  • 양 표면 모두 후보 풀을 넓게 over-fetch(searchrank.FetchLimit) → FTS가 limit
    아래로 매긴 좋은 매치도 리랭크가 끌어올릴 수 있음.
  • CLI(internal/cli/search.go)와 MCP(internal/mcp/handler_query.go) 양쪽 배선.

실측 (ccg build ./internal, 1523 노드)

쿼리 before after
rerank isAlnum #1 Rerank #1
fetch limit 못 찾음 FetchLimit #1

검증

  • CGO_ENABLED=1 go test -tags "fts5" ./... -count=1 — 전체 green
  • go vet 클린
  • 리랭크 단위 테스트 12종 (경계/오타/멀티토큰/서브토큰/name>path/동점 stable/limit/Levenshtein/splitIdentifier)

알려진 한계 / 후속

FTS unicode61 + prefix-only 토크나이저가 camelCase를 안 쪼개, 순수 오타·내부
단어 쿼리는 FTS가 0건 반환 → 리랭크가 recall을 못 늘림(precision만 개선). 다음
레버는 camelCase-aware FTS 토크나이징 (별도 태스크로 계획됨).

🤖 Generated with Claude Code

The CLI `ccg search` and the MCP `search` tool returned FTS candidates in
raw BM25 order. Introduce internal/searchrank, a dependency-free reranker that
fuses the FTS rank with two structural signals via Reciprocal Rank Fusion:

- name fuzzy similarity (rune Levenshtein over the whole name and camelCase
  sub-tokens, plus the run-together query for typos), and
- path proximity (query tokens matching file-path segments).

Name is weighted above path so an exact-name match outranks a mere same-file
hit. Both surfaces over-fetch a wider candidate pool (searchrank.FetchLimit)
so reranking can promote good matches FTS ranked below the caller's limit.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@tae2089
tae2089 merged commit c6c9300 into main Jul 11, 2026
1 check failed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant